//===========================================================================//
// File:	vector4d.cc                                                      //
// Contents: Implementation details for vector classes                       //
//---------------------------------------------------------------------------//
// Copyright (C) Microsoft Corporation. All rights reserved.                 //
//===========================================================================//

#include "StuffHeaders.hpp"

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Vector4D ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

const Vector4D
	Vector4D::Identity(0.0f,0.0f,0.0f,0.0f);

//
//###########################################################################
//###########################################################################
//
bool
	Stuff::Small_Enough(const Vector4D &V,Scalar e)
{
	Check_Object(&V);
	return V.x*V.x + V.y*V.y + V.z*V.z + V.w*V.w <= e;
}

//
//###########################################################################
//###########################################################################
//
bool
	Stuff::Close_Enough(const Vector4D &V1, const Vector4D &V2, Scalar e)
{
	Check_Object(&V1);
	Check_Object(&V2);

	Vector4D v(V1.x-V2.x, V1.y-V2.y, V1.z-V2.z, V1.w-V2.w);
	return Stuff::Small_Enough(v, e);
}

//
//###########################################################################
//###########################################################################
//
Vector4D&
	Vector4D::Multiply(
		const Vector4D& v,
		const AffineMatrix4D& m
	)
{
	Check_Pointer(this);
	Check_Object(&v);
	Check_Object(&m);
	Verify(this != &v);

	x = v.x*m(0,0) + v.y*m(1,0) + v.z*m(2,0) + v.w*m(3,0);
	y = v.x*m(0,1) + v.y*m(1,1) + v.z*m(2,1) + v.w*m(3,1);
	z = v.x*m(0,2) + v.y*m(1,2) + v.z*m(2,2) + v.w*m(3,2);
	w = v.w;
	return *this;
}

//
//###########################################################################
//###########################################################################
//
Vector4D&
	Vector4D::Multiply(
		const Vector4D& v,
		const Matrix4D& m
	)
{
	Check_Pointer(this);
	Check_Object(&v);
	Check_Object(&m);
	Verify(this != &v);

	x = v.x*m(0,0) + v.y*m(1,0) + v.z*m(2,0) + v.w*m(3,0);
	y = v.x*m(0,1) + v.y*m(1,1) + v.z*m(2,1) + v.w*m(3,1);
	z = v.x*m(0,2) + v.y*m(1,2) + v.z*m(2,2) + v.w*m(3,2);
	w = v.x*m(0,3) + v.y*m(1,3) + v.z*m(2,3) + v.w*m(3,3);
	return *this;
}

//
//###########################################################################
//###########################################################################
//
Vector4D&
	Vector4D::Multiply(
		const Vector3D& v,
		const Matrix4D& m
	)
{
	Check_Pointer(this);
	Check_Object(&v);
	Check_Object(&m);

	x = v.x*m(0,0) + v.y*m(1,0) + v.z*m(2,0);
	y = v.x*m(0,1) + v.y*m(1,1) + v.z*m(2,1);
	z = v.x*m(0,2) + v.y*m(1,2) + v.z*m(2,2);
	w = v.x*m(0,3) + v.y*m(1,3) + v.z*m(2,3);
	return *this;
}

#if 0
// it is now inline likely this has to happen to most of the other functions
//###########################################################################
//###########################################################################
//
Vector4D&
	Vector4D::Multiply(
		const Point3D& v,
		const Matrix4D& m
	)
{
	Check_Pointer(this);
	Check_Object(&v);
	Check_Object(&m);

	x = v.x*m(0,0) + v.y*m(1,0) + v.z*m(2,0) + m(3,0);
	y = v.x*m(0,1) + v.y*m(1,1) + v.z*m(2,1) + m(3,1);
	z = v.x*m(0,2) + v.y*m(1,2) + v.z*m(2,2) + m(3,2);
	w = v.x*m(0,3) + v.y*m(1,3) + v.z*m(2,3) + m(3,3);
	return *this;
}
#endif

//
//###########################################################################
//###########################################################################
//
#if !defined(Spew)
	void
		Spew(
			const char* group,
			const Vector4D &vector
		)
	{
		Check_Object(&vector);
		SPEW((group, "<%4f,%4f,%4f,%4f>", vector.x, vector.y, vector.z, vector.w));
	}
#endif

Vector4D&
	Vector4D::MultiplySetClip(
		const Point3D &v,
		const Matrix4D &m,
		int *clipper
	)
{
	Check_Pointer(this);
	Check_Object(&v);
	Check_Object(&m);

#if USE_ASSEMBLER_CODE
	Scalar *f = &x;
	_asm {
		mov         edi, v

		fld			dword ptr [edi]			//	v.x

		mov         esi, m

		fld			dword ptr [edi+4]		//	v.y
		fld			dword ptr [edi+8]		//	v.z

		mov         edi, f

		fld         dword ptr [esi+34h]		//	m[1][3]
		fmul        st, st(2)				//	v.y

		fld         dword ptr [esi+38h]		//	m[2][3]
		fmul        st, st(2)				//	v.z

		fxch		st(1)
		fadd        dword ptr [esi+3Ch]		//	m[3][3]

		fld         dword ptr [esi+30h]		//	m[0][3]
		fmul        st, st(5)				//	v.x

		fxch		st(2)
		faddp       st(1),st

		fld         dword ptr [esi+14h]		//	m[1][1]
		fmul        st, st(4)				//	v.y

		fxch		st(2)
		faddp       st(1),st

		fld         dword ptr [esi+18h]		//	m[2][1]
		fmul        st, st(3)				//	v.z

		fxch		st(1)
		fstp        dword ptr [edi+0Ch]		//	w

		fadd        dword ptr [esi+1Ch]		//	m[3][1]

		fld         dword ptr [esi+10h]		//	m[0][1]
		fmul        st, st(5)				//	v.x

		fxch		st(2)
		faddp       st(1),st

		fld         dword ptr [esi+24h]		//	m[1][2]
		fmul        st, st(4)				//	v.y

		fxch		st(2)
		faddp       st(1),st

		fld         dword ptr [esi+28h]		//	m[2][2]
		fmul        st, st(3)				//	v.z

		fxch		st(1)
		fstp        dword ptr [edi+4]		//	y

		fadd        dword ptr [esi+2Ch]		//	m[3][2]

		fld         dword ptr [esi+20h]		//	m[0][2]
		fmul        st, st(5)				//	v.x

		fxch		st(2)
		faddp       st(1),st

		fld         dword ptr [esi+4]		//	m[1][0]
		fmul        st, st(4)				//	v.y

		fxch		st(2)
		faddp       st(1),st

		fld         dword ptr [esi+8]		//	m[2][0]
		fmul        st, st(3)				//	v.z

		fxch		st(1)
		fstp        dword ptr [edi+8]		//	z

		fadd        dword ptr [esi+0Ch]		//	m[3][0]

		fld         dword ptr [esi]			//	m[0][0]
		fmul        st, st(5)				//	v.x

		fxch		st(2)
		faddp       st(1),st

		faddp       st(1),st

		//	get rid of x, y, z
		fstp		st(1)
		fstp		st(1)
		fstp		st(1)

		fstp        dword ptr [edi]			//	x

	}
#else
	x = v.x*m(0,0) + v.y*m(1,0) + v.z*m(2,0) + m(3,0);
	y = v.x*m(0,1) + v.y*m(1,1) + v.z*m(2,1) + m(3,1);
	z = v.x*m(0,2) + v.y*m(1,2) + v.z*m(2,2) + m(3,2);
	w = v.x*m(0,3) + v.y*m(1,3) + v.z*m(2,3) + m(3,3);
#endif

	*clipper = 0;

	if(w <= z)
	{
		*clipper |= 32;
	}

	if(z < 0.0f)
	{
		*clipper |= 16;
	}

	if(x < 0.0f)
	{
		*clipper |= 8;
	}

	if(w < x)
	{
		*clipper |= 4;
	}

	if(y < 0.0f)
	{
		*clipper |= 2;
	}

	if(w < y)
	{
		*clipper |= 1;
	}

	return *this;
}
